<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<input type="file" id="file" accept="video/*">

<div id="result" class="result"></div>
<script>
  file.onchange = function (event) {
    const file = event.target.files[0];
    // 开始识别
    const reader = new FileReader();
    reader.onload = function (event) {
      const arrBuffer = event.target.result;
      handleBuffer(arrBuffer, file.name);
    };
    reader.readAsArrayBuffer(file);

    // 显示loading
    // result.innerHTML = '<ui-loading></ui-loading>';
  };

  const handleBuffer = function (buffer, name) {
    if (/\//.test(name)) {
      name = name.split('/').slice(-1)[0];
    }

    name = name.split('.')[0];

    // 创建音频上下文
    const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
    // arrayBuffer转audioBuffer
    audioCtx.decodeAudioData(buffer, function(audioBuffer) {
      // audioBuffer就是AudioBuffer
      const blob = bufferToWave(audioBuffer, audioBuffer.length);
      // 使用Blob地址
      const blobUrl = URL.createObjectURL(blob);

      result.innerHTML = `<h4>试听</h4>
            <audio src="${blobUrl}" controls></audio>
            <p>点击<a href="${blobUrl}" download="${name}.wav">这里下载音频</a>。</p>
        `;
    });
  };

  function bufferToWave(abuffer, len) {
    var numOfChan = abuffer.numberOfChannels,
        length = len * numOfChan * 2 + 44,
        buffer = new ArrayBuffer(length),
        view = new DataView(buffer),
        channels = [],
        offset = 0,
        pos = 0;

    // write WAVE header
    setUint32(0x46464952);                         // "RIFF"
    setUint32(length - 8);                         // file length - 8
    setUint32(0x45564157);                         // "WAVE"
    setUint32(0x20746D66);                         // "fmt " chunk
    setUint32(16);                                 // length = 16
    setUint16(1);                                  // PCM (uncompressed)
    setUint16(numOfChan);                          // number of channels
    setUint32(abuffer.sampleRate);                 // sample rate
    setUint32(abuffer.sampleRate * 2 * numOfChan);  // avg. bytes/sec
    setUint16(numOfChan * 2);                      // block-align
    setUint16(16);                                 // 16-bit (hardcoded in this demo)
    setUint32(0x61746164);                         // "data" - chunk
    setUint32(length - pos - 4);                   // chunk length

    // write interleaved data
    for (var i = 0; i < abuffer.numberOfChannels; i++) {
      channels.push(abuffer.getChannelData(i));
    }

    while (pos < length) {
      for (var i = 0; i < numOfChan; i++) {
        // clamp
        var sample = Math.max(-1, Math.min(1, channels[i][offset]));
        // scale to 16-bit signed int
        sample = (0.5 + sample < 0 ? sample * 32768 : sample * 32767)|0;
        // write 16-bit sample
        view.setInt16(pos, sample, true);
        pos += 2;
      }
      offset++;
    }

    // create Blob
    return new Blob([buffer], {type: "audio/wav"});

    function setUint16(data) {
      view.setUint16(pos, data, true);
      pos += 2;
    }

    function setUint32(data) {
      view.setUint32(pos, data, true);
      pos += 4;
    }
  }
</script>
</body>
</html>
